package com.climber.android.component.webview.mvp.presenter

import android.app.Application
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.net.http.SslError
import android.os.Build
import android.text.TextUtils
import android.webkit.*
import androidx.lifecycle.LifecycleOwner
import com.google.gson.JsonParser
import com.climber.android.commonres.app.AppAccount
import com.climber.android.commonres.util.UIHelper
import com.climber.android.component.webview.R
import com.climber.android.component.webview.mvp.contract.BaseWebContract
import com.climber.android.component.webview.mvp.ui.OverrideUrlLoadingSubChildListener
import io.ganguo.library.dswebview.BridgeWebListener
import io.ganguo.library.dswebview.CompletionHandler
import io.ganguo.library.dswebview.DSWebView
import io.ganguo.library.klog.KLog
import io.ganguo.library.mvp.ui.mvp.BasePresenter
import io.ganguo.library.mvp.ui.mvp.di.scope.ActivityScope
import io.ganguo.library.mvp.util.*
import java.util.*
import javax.inject.Inject

/**
 * Created by Mikes at 2019/5/5 11:34 AM
 * 展示 Presenter 的用法
 */
@ActivityScope
class BaseWebPresenter @Inject
constructor(model: BaseWebContract.Model, rootView: BaseWebContract.View) :
    BasePresenter<BaseWebContract.Model, BaseWebContract.View>(model, rootView) {

    companion object {
        private val ERROR_CODE_CATCH: MutableList<Int>
        private val ERROR_TITLE_CATCH: MutableList<String>

        init {
            ERROR_CODE_CATCH = ArrayList()
            //断网，网络连接超时
            ERROR_CODE_CATCH.add(WebViewClient.ERROR_HOST_LOOKUP)
            ERROR_CODE_CATCH.add(WebViewClient.ERROR_CONNECT)
            ERROR_CODE_CATCH.add(WebViewClient.ERROR_TIMEOUT)
            //
            ERROR_CODE_CATCH.add(WebViewClient.ERROR_FILE_NOT_FOUND)

            ERROR_TITLE_CATCH = ArrayList()
            ERROR_TITLE_CATCH.add("404 Not Found")
            ERROR_TITLE_CATCH.add("网页无法打开")
        }
    }

    private var webViewShown = false
    private var showError = false

    private var overrideUrlLoadingSubChildListener: OverrideUrlLoadingSubChildListener? = null

    @Inject
    @JvmField
    var mApplication: Application? = null

    private val defaultWebViewClient = object : WebViewClient() {
        override fun onReceivedError(
            view: WebView?,
            errorCode: Int,
            description: String?,
            failingUrl: String?
        ) {
            checkShouldShowErrorView(errorCode, description ?: "", failingUrl ?: "")
        }

        override fun onReceivedSslError(
            view: WebView?,
            handler: SslErrorHandler?,
            error: SslError?
        ) {
            handler?.proceed()
            super.onReceivedSslError(view, handler, error)
        }

        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)

            val webTitle = view?.title ?: ""
            KLog.d(DSWebView.DS_TAG, webTitle)
            if (TextUtils.isEmpty(webTitle)) {
                return
            }
            if (webTitle.startsWith("https://") || webTitle.startsWith("http://")) {
                return
            }
            if (mRootView.isSupportDynamicTitle()) {
                mRootView.setWebTitle(webTitle)
            }
        }

        override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
            if(view == null || url == null) return false

            if (overrideUrlLoadingSubChildListener != null
                && overrideUrlLoadingSubChildListener!!.shouldOverrideUrlLoading(view, url)) {
                //子类已根据具体业务拦截.
                return true
            } else if (url.startsWith("tel:")) {
                try {
                    val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
                    ActivityUtils.startActivity(intent)
                } catch (e: ActivityNotFoundException) {
                    return false
                }

                return true
            } else if (!(url.startsWith("http") || url.startsWith("https"))) {
                return true
            }

            mRootView.updateWebCloseBtnVisibility(true)

            return false
        }
    }

    private val defaultWebChromeClient = object : WebChromeClient() {
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
            KLog.i(DSWebView.DS_TAG, newProgress)
            if (newProgress > 70) {
                if (mRootView.showLoadingAnim()) {
                    mRootView.hideWebLoading()
                }

                if (!showError && !webViewShown) {
                    webViewShown = true
                    mRootView.webViewShown()
                }
            }
        }

        override fun onReceivedTitle(view: WebView?, title: String?) {
            super.onReceivedTitle(view, title)
            checkShouldShowErrorView(title ?: "")
        }
    }

    private val dsBridgeListener = object : BridgeWebListener {
        override fun onClose(msg: Any?): Boolean {
            return true
        }

        override fun setTitle(msg: Any?, handler: CompletionHandler<String>?) {
            if (msg == null) return
            val json = JsonElementHelper.jsonObjectValue(JsonParser().parse(msg.toString()))
            if (json != null && JsonElementHelper.stringValue(json.get("title")) != null) {
                mRootView.setWebTitle(JsonElementHelper.stringValue(json.get("title")))
            }
        }
    }

    fun setOverrideUrlLoadingSubChildListener(listener: OverrideUrlLoadingSubChildListener) {
        this.overrideUrlLoadingSubChildListener = listener
    }

    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
        this.mApplication = null
    }

    fun initBridgeWebviewConfig(webView: DSWebView) {
        showError = false
        webViewShown = false

        webView.isShowProgressBar = true
        val defaultBarDrawable =
            mApplication!!.resources.getDrawable(R.drawable.web_bridge__progress_bar_style)
        webView.setProgressBarDrawable(defaultBarDrawable)
        webView.setWebViewDebuggingEnabled(true)

        //启用数据库
        val dir = mApplication!!.getDir("database", Context.MODE_PRIVATE).path
        //设置定位的数据库路径 Deprecated from API 19
        webView.settings.setGeolocationDatabasePath(dir)

        webView.setBridgeWebListener(dsBridgeListener)

        webView.setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
            downloadByOutBrowser(
                url
            )
        }
        webView.webViewClient = defaultWebViewClient
        webView.setWebChromeClient(defaultWebChromeClient)

        //use dsBridge in javaScript
        webView.addJavascriptObject(this, "")
    }

    // 跳转外部浏览器下载
    private fun downloadByOutBrowser(url: String) {
        val intent = Intent(Intent.ACTION_VIEW)
        intent.addCategory(Intent.CATEGORY_BROWSABLE)
        intent.data = Uri.parse(url)

        try {
            mRootView.getActivity().startActivity(Intent.createChooser(intent, ""))
        } catch (e: Exception) {
            // do nothing if occurs error when click download link.
        }

    }


    fun evaluateJavascript(javascript: String) {
        KLog.d(DSWebView.DS_TAG, "evaluateJavascript ($javascript)")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mRootView.getWebView().evaluateJavascript(javascript) { value -> }
        } else {
            mRootView.getWebView().loadUrl(javascript)
        }
    }

    fun checkShouldShowErrorView(
        errorCode: Int,
        description: CharSequence,
        failingUrl: CharSequence
    ) {
        KLog.d(
            DSWebView.DS_TAG,
            "[DEBUG: native]" +
                    mRootView.preferHtmlUrl() + " " +
                    "occurs error \n" +
                    "Print:<errorCode : " + errorCode + ", description : " + description + ", failingUrl : " + failingUrl + ">"
        )

        val showShowErrorView =
            !NetworkUtils.isNetworkConnected() || ERROR_CODE_CATCH.contains(errorCode)
        if (showShowErrorView) {
            showError = true
            mRootView.showWebViewError("")
        }
    }

    fun checkShouldShowErrorView(errorTitle: String) {
        KLog.d(DSWebView.DS_TAG, "webView occurs error, errorTitle : $errorTitle")

        var catchErrorTitle = false
        for (title in ERROR_TITLE_CATCH) {
            if (errorTitle.contains(title)) {
                catchErrorTitle = true
                break
            }
        }

        val showShowErrorView = !NetworkUtils.isNetworkConnected() || catchErrorTitle
        if (showShowErrorView) {
            mRootView.showWebViewError("")
        }
    }

    //subclass must call it
    fun loadHtmlFile() {
        this.loadHtmlFile(mRootView.preferHtmlUrl())
    }

    fun loadHtmlFile(preferUrl: String) {
        if (!NetworkUtils.isNetworkConnected()) {
            mRootView.showWebViewError(preferUrl)
            return
        }

        //check client token before loading webView
        if (mRootView.showLoadingAnim()) {
            mRootView.showWebLoading()
        }

        if (TextUtils.isEmpty(preferUrl)) {
            mRootView.showWebViewError("")
        } else {
            mRootView.getWebView().loadUrl(preferUrl)
        }
    }

    fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    }

    //provide method to javaScript
    @JavascriptInterface
    fun closeAndroid(msg: Any, handler: CompletionHandler<String>) {
        mRootView.killMyself()
    }

    /**
     * APP环境变量
     */
    @JavascriptInterface
    fun getWebAppSettings(msg: Any, handler: CompletionHandler<String>) {
        val appSettingsMap = HashMap<String, String>()
        appSettingsMap["platform"] = "android"
        appSettingsMap["version"] = "" + AppUtils.getAppVersionName()
        appSettingsMap["versionCode"] = "" + AppUtils.getAppVersionCode()

        handler.complete(GsonUtils.toJson(appSettingsMap))
    }

    /**
     * 当前用户信息
     */
    @JavascriptInterface
    fun getUserInfo(msg: Any, handler: CompletionHandler<String>) {
        if (AppAccount.isAuthenticated()) {
            val appSettingsMap = HashMap<String, String>()

            handler.complete(GsonUtils.toJson(appSettingsMap))
        } else {
            handler.complete("{}")
        }
    }


    /**
     * 拨打电话
     */
    @JavascriptInterface
    fun phoneCall(msg: Any?, handler: CompletionHandler<String>) {
        if (msg == null) {
            UIHelper.showUnknownError()
            return
        }
        val json = JsonElementHelper.jsonObjectValue(JsonParser().parse(msg.toString()))
        if (json == null) {
            UIHelper.showUnknownError()
            return
        }

        val telNumber = JsonElementHelper.stringValue(json.get("tel"))
        val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:$telNumber"))
        ActivityUtils.startActivity(intent)
    }

}
